<?php

namespace QingSen\gridfs;

use GuzzleHttp\Client;
use RuntimeException;
use GuzzleHttp\Exception\GuzzleException;

/**
 * 文件资源服务SDK
 *
 */
class GridFileService implements GridFileUploadInterface
{
    private const BASE_URI                       = 'https://file.kanghao.shop';
    private const URI_UPLOAD_AUDIO               = '/file/Audio/upload';
    private const URI_UPLOAD_AUDIO_TRANSCODE     = '/file/audio_transcode/transcode';

    private const URI_UPLOAD_FILE                = '/file/file/upload';
    private const URI_UPLOAD_VIDEO               = '/file/video/upload';
    private const URI_UPLOAD_IMAGE               = '/file/image/upload';
    private const URI_UPLOAD_IMAGE_FORMAT        = '/file/image_format/format';
    private const URI_UPLOAD_IMAGE_CROP          = '/file/image_crop/crop';
    private const URI_UPLOAD_IMAGE_FIT           = '/file/image_fit/fit';
    private const URI_UPLOAD_IMAGE_RESIZE        = '/file/image_resize/resize';
    private const URI_UPLOAD_IMAGE_INSERT        = '/file/image_insert/insert';

    private const URI_MANAGER_DOC                = '/file/manager/doc';
    private const URI_MANAGER_QUERY              = '/file/manager/query';
    private const URI_MANAGER_DELETE             = '/file/manager/delete';

    public const IMAGE_TEMPLATE_SMALL           = 'small';
    public const IMAGE_TEMPLATE_MEDIUM          = 'medium';
    public const IMAGE_TEMPLATE_LARGE           = 'large';
    public const IMAGE_TEMPLATE_LARGE16BY9      = 'large16by9';
    public const IMAGE_TEMPLATE_AVATAR          = 'avatar';
    public const IMAGE_TEMPLATE_ICON32          = 'icon32';
    public const IMAGE_TEMPLATE_ICON64          = 'icon64';
    public const IMAGE_TEMPLATE_ICON128         = 'icon128';
    public const IMAGE_TEMPLATE_ICON256         = 'icon256';
    public const IMAGE_TEMPLATE_WH100           = 'wh100';
    public const IMAGE_TEMPLATE_WH200           = 'wh200';
    public const IMAGE_TEMPLATE_WH300           = 'wh300';
    public const IMAGE_TEMPLATE_WH400           = 'wh400';

    public const IMAGE_TEMPLATE_W100            = 'w100';
    public const IMAGE_TEMPLATE_W200            = 'w200';
    public const IMAGE_TEMPLATE_W300            = 'w300';
    public const IMAGE_TEMPLATE_W400            = 'w400';
    public const IMAGE_TEMPLATE_H100            = 'h100';
    public const IMAGE_TEMPLATE_H200            = 'h200';
    public const IMAGE_TEMPLATE_H300            = 'h300';
    public const IMAGE_TEMPLATE_H400            = 'h400';

    /**
     * 上传的文件
     *
     * @var array
     */
    private $file1;

    /**
     * 上传的第二个文件
     *
     * @var array
     */
    private $file2;

    /**
     * 上传处理器
     * @see http://file.master.cn/document/
     * @param (string|bin)[] $file1 [文件名,文件内容]
     * @param (string|bin)[] $file2 [文件名,文件内容]
     * @return GridFileUploadInterface
     */
    public static function upload($file1, $file2 = null)
    {
        $instance = new self();
        $instance->file1 = $file1;

        if (false == is_null($file2)) {
            $instance->file = $file2;
        }

        return $instance;
    }

    public function image()
    {
        $content = $this->tryPostFile(self::URI_UPLOAD_IMAGE);

        return ImageMetadata::from($content);
    }

    public function imageFormat($quality = 100, $format = 'jpg')
    {
        $params         = [
            'quality'   => $quality,
            'format'    => $format,
        ];

        $content       = $this->tryPostFile(self::URI_UPLOAD_IMAGE_FORMAT, $params);
        return ImageMetadata::from($content);
    }

    public function imageCrop($width, $height, $x = null, $y = null, $quality = 100, $format = 'jpg')
    {
        $param          = [
            'width'     => $width,
            'height'    => $height,
            'quality'   => $quality,
            'format'    => $format,
        ];
        if (false == is_null($x)) {
            $param['x'] = $x;
        }
        if (false == is_null($y)) {
            $param['y'] = $y;
        }

        $content       = $this->tryPostFile(self::URI_UPLOAD_IMAGE_CROP, $param);
        return ImageMetadata::from($content);
    }

    public function imageFit($template = 'small', $position = 5, $quality = 100, $format = 'jpg')
    {
        $param          = [
            'template'  => $template,
            'position'  => $position,
            'quality'   => $quality,
            'format'    => $format,
        ];

        $content       = $this->tryPostFile(self::URI_UPLOAD_IMAGE_FIT, $param);
        return ImageMetadata::from($content);
    }

    public function imageResize($template = 'w100', $quality = 100, $format = 'jpg')
    {
        $parma          = [
            'template'  => $template,
            'quality'   => $quality,
            'format'    => $format,
        ];

        $content       = $this->tryPostFile(self::URI_UPLOAD_IMAGE_RESIZE, $parma);
        return ImageMetadata::from($content);
    }

    public function imageInsert($quality = 100, $format = 'jpg', $position = 1, $x = 0, $y = 0)
    {
        $param = [
            'quality'   => $quality,
            'format'    => $format,
            'position'  => $position,
            'x'         => $x,
            'y'         => $y
        ];

        $content       = $this->tryPostFile(self::URI_UPLOAD_IMAGE_INSERT, $param);
        return ImageMetadata::from($content);
    }

    public function audio()
    {
        $response       = $this->tryPostFile(self::URI_UPLOAD_AUDIO);
        return AudioMetadata::from($response);
    }

    public function audioTranscode($format = 'mp3', $clip = [], $channels = 2, $kbps = 256)
    {
        $param = [
            'format'    => $format,
            'clip'      => $clip,
            'channels'  => $channels,
            'kbps'      => $kbps,
        ];
        $response       = $this->tryPostFile(self::URI_UPLOAD_AUDIO_TRANSCODE, $param);
        return AudioMetadata::from($response);
    }

    public function file()
    {
        $response       = $this->tryPostFile(self::URI_UPLOAD_FILE);
        return FileMetadata::from($response);
    }

    public function video()
    {
        $response       = $this->tryPostFile(self::URI_UPLOAD_VIDEO);
        return VideoMetadata::from($response);
    }

    /**
     * 上传文件
     * @param string $uri 上传处理器
     * @param array $param 附加参数
     * @return string
     * @throws RuntimeException
     * @throws GuzzleException
     */
    private function tryPostFile($uri, $param = [])
    {
        // 配置cookie
        $isActive       = PHP_SESSION_ACTIVE == session_status();
        if (false == $isActive) {
            session_start();
        }

        $cookie         = new \GuzzleHttp\Cookie\SetCookie();
        $cookie->setName('PHPSESSID');
        $cookie->setValue(session_id());
        $cookie->setDomain('file.kanghao.shop');

        $jar            = new \GuzzleHttp\Cookie\CookieJar();
        $jar->setCookie($cookie);

        // 配置请求体
        [$name, $bin]   = $this->file1;

        $multi[]        = [
            'name'      => 'file',
            'filename'  => $name,
            'contents'  => $bin,
        ];

        if (is_array($this->file2)) {
            $multi[0]['name'] = 'layer_0';

            [$name, $bin]   = $this->file2;
            $multi[]        = [
                'name'      => 'layer_1',
                'filename'  => $name,
                'contents'  => $bin,
            ];
        }

        // 附加字段
        foreach ($param as $key => $value) {
            $multi[]        = [
                'name'      => $key,
                'contents'  => $value,
            ];
        }

        // 发起请求
        $client        = new Client(['base_uri'  => self::BASE_URI]);
        $option        = [
            \GuzzleHttp\RequestOptions::COOKIES     => $jar,
            \GuzzleHttp\RequestOptions::MULTIPART   => $multi,
        ];

        return $client->post($uri, $option)->getBody()->getContents();
    }
}
